package service

import (
	"encoding/base64"
	"errors"
	"fmt"
	"time"

	"gitee.com/huangxinbo/xcas/internal/app/base"
	"gitee.com/huangxinbo/xcas/internal/constants"
	"gitee.com/huangxinbo/xcas/internal/dao"
	"gitee.com/huangxinbo/xcas/internal/model"
	"gitee.com/huangxinbo/xcas/internal/model/db_model"
	"gitee.com/huangxinbo/xcas/pkg/password"
	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
	"go.uber.org/zap"
)

type UserService struct {
	base    *base.Base
	dao     *dao.DAO
	service *Service
}

func NewUserService(base *base.Base, dao *dao.DAO, service *Service) *UserService {
	return &UserService{
		base:    base,
		dao:     dao,
		service: service,
	}
}

func (s *UserService) CreateUser(ctx *gin.Context, req *model.UserCreateRequest) (*db_model.User, error) {
	// Check if email already exists
	existingUser, err := s.dao.UserDAO.GetByEmail(ctx, req.Email)
	if err != nil {
		return nil, err
	}
	if existingUser != nil {
		return nil, errors.New("email already exists")
	}

	user := &db_model.User{
		Name:  req.Name,
		Email: req.Email,
	}

	// 只有当密码不为空时才设置密码字段
	if req.Password != "" {
		user.Password = &req.Password // In production, password should be hashed here
	}

	if err := s.dao.UserDAO.Create(ctx, user); err != nil {
		return nil, err
	}

	s.base.Logger.Info("User created successfully", zap.String("id", user.ID))
	return user, nil
}

func (s *UserService) GetUser(ctx *gin.Context, id string) (*db_model.User, error) {
	user, err := s.dao.UserDAO.GetByID(ctx, id)
	if err != nil {
		return nil, err
	}
	if user == nil {
		return nil, errors.New("user not found")
	}
	return user, nil
}

func (s *UserService) GetUserByEmail(ctx *gin.Context, email string) (*db_model.User, error) {
	user, err := s.dao.UserDAO.GetByEmail(ctx, email)
	if err != nil {
		return nil, err
	}
	return user, nil
}

func (s *UserService) ListUsers(ctx *gin.Context, offset, limit int) ([]*db_model.User, int64, error) {
	if limit <= 0 {
		limit = 10
	}
	if limit > 100 {
		limit = 100
	}

	return s.dao.UserDAO.List(ctx, offset, limit)
}

// UpdateUserAfterVerification 验证后更新用户信息（设置用户名、密码和验证时间）
func (s *UserService) UpdateUserAfterVerification(ctx *gin.Context, email, name, plainPassword string) error {
	user, err := s.dao.UserDAO.GetByEmail(ctx, email)
	if err != nil {
		return err
	}
	if user == nil {
		return errors.New("user not found")
	}

	// 加密密码
	hashedPassword, err := password.HashPassword(plainPassword)
	if err != nil {
		s.base.Logger.Error("Failed to hash password", zap.Error(err))
		return errors.New("failed to process password")
	}

	// 更新用户信息
	user.Name = name
	user.Password = &hashedPassword
	now := time.Now()
	user.VerifiedAt = &now

	if err := s.dao.UserDAO.Update(ctx, user); err != nil {
		return err
	}

	s.base.Logger.Info("User updated after verification",
		zap.String("email", email),
		zap.String("name", name))
	return nil
}

// VerifyPassword 验证密码
func (s *UserService) VerifyPassword(hashedPassword *string, plainPassword string) bool {
	if hashedPassword == nil {
		return false
	}
	return password.CheckPassword(plainPassword, *hashedPassword)
}

// UpdateUser 更新用户信息
func (s *UserService) UpdateUser(ctx *gin.Context, userID string, req *model.UserUpdateRequest) (*db_model.User, error) {
	// 获取用户
	user, err := s.dao.UserDAO.GetByID(ctx, userID)
	if err != nil {
		return nil, err
	}
	if user == nil {
		return nil, errors.New("user not found")
	}

	// 更新可修改的字段
	if req.Name != nil {
		user.Name = *req.Name
	}
	if req.FirstName != nil {
		user.FirstName = req.FirstName
	}
	if req.LastName != nil {
		user.LastName = req.LastName
	}
	if req.Image != nil {
		user.Image = req.Image
	}
	if req.Address != nil {
		user.Address = req.Address
	}
	if req.Region != nil {
		user.Region = req.Region
	}
	if req.Mobile != nil {
		user.Mobile = req.Mobile
	}

	// 设置更新时间
	now := time.Now()
	user.UpdatedAt = &now

	// 保存更新
	if err := s.dao.UserDAO.Update(ctx, user); err != nil {
		return nil, err
	}

	return user, nil
}

// SendEmailCaptcha 发送邮箱修改验证码
func (s *UserService) SendEmailCaptcha(ctx *gin.Context, userID, newEmail string) error {
	// 获取当前用户
	user, err := s.dao.UserDAO.GetByID(ctx, userID)
	if err != nil {
		return err
	}
	if user == nil {
		return errors.New("user not found")
	}

	// 检查新邮箱是否已被其他用户使用
	existingUser, err := s.dao.UserDAO.GetByEmail(ctx, newEmail)
	if err != nil {
		return err
	}
	if existingUser != nil && existingUser.ID != userID {
		return errors.New("email already exists")
	}

	// 使用注入的 VerificationService 发送邮箱验证码
	_, err = s.service.VerificationService.CreateEmailCaptcha(ctx, newEmail)
	if err != nil {
		return err
	}

	return nil
}

// UpdateUserEmail 更新用户邮箱
func (s *UserService) UpdateUserEmail(ctx *gin.Context, userID string, req *model.UserEmailUpdateRequest) error {
	// 获取当前用户
	user, err := s.dao.UserDAO.GetByID(ctx, userID)
	if err != nil {
		return err
	}
	if user == nil {
		return errors.New("user not found")
	}

	// 使用注入的 VerificationService 验证验证码
	valid, err := s.service.VerificationService.VerifyToken(ctx, req.Email, req.Captcha, db_model.VerificationTypeEmail)
	if err != nil {
		return err
	}
	if !valid {
		return errors.New("invalid captcha")
	}

	// 检查新邮箱是否已被其他用户使用
	existingUser, err := s.dao.UserDAO.GetByEmail(ctx, req.Email)
	if err != nil {
		return err
	}
	if existingUser != nil && existingUser.ID != userID {
		return errors.New("email already exists")
	}

	// 更新邮箱
	user.Email = req.Email
	now := time.Now()
	user.UpdatedAt = &now

	// 保存更新
	if err := s.dao.UserDAO.Update(ctx, user); err != nil {
		return err
	}

	return nil
}

// SendMobileCaptcha 发送手机号修改验证码
func (s *UserService) SendMobileCaptcha(ctx *gin.Context, userID, newMobile string) error {
	// 获取当前用户
	user, err := s.dao.UserDAO.GetByID(ctx, userID)
	if err != nil {
		return err
	}
	if user == nil {
		return errors.New("user not found")
	}

	// 检查新手机号是否已被其他用户使用
	existingUser, err := s.dao.UserDAO.GetByMobile(ctx, newMobile)
	if err != nil {
		return err
	}
	if existingUser != nil && existingUser.ID != userID {
		return errors.New("mobile already exists")
	}

	// 使用注入的 VerificationService 发送手机号验证码
	_, err = s.service.VerificationService.CreateMobileCaptcha(ctx, newMobile)
	if err != nil {
		return err
	}

	return nil
}

// UpdateUserMobile 更新用户手机号
func (s *UserService) UpdateUserMobile(ctx *gin.Context, userID string, req *model.UserMobileUpdateRequest) error {
	// 获取当前用户
	user, err := s.dao.UserDAO.GetByID(ctx, userID)
	if err != nil {
		return err
	}
	if user == nil {
		return errors.New("user not found")
	}

	// 使用注入的 VerificationService 验证验证码
	valid, err := s.service.VerificationService.VerifyToken(ctx, req.Mobile, req.Captcha, db_model.VerificationTypeMobile)
	if err != nil {
		return err
	}
	if !valid {
		return errors.New("invalid captcha")
	}

	// 检查新手机号是否已被其他用户使用
	existingUser, err := s.dao.UserDAO.GetByMobile(ctx, req.Mobile)
	if err != nil {
		return err
	}
	if existingUser != nil && existingUser.ID != userID {
		return errors.New("mobile already exists")
	}

	// 更新手机号
	user.Mobile = &req.Mobile
	now := time.Now()
	user.UpdatedAt = &now

	// 保存更新
	if err := s.dao.UserDAO.Update(ctx, user); err != nil {
		return err
	}

	return nil
}

// UpdateUserPassword 更新用户密码
func (s *UserService) UpdateUserPassword(ctx *gin.Context, userID string, req *model.UserPasswordUpdateRequest) error {
	// 获取用户
	user, err := s.dao.UserDAO.GetByID(ctx, userID)
	if err != nil {
		return err
	}
	if user == nil {
		return errors.New("user not found")
	}

	// 检查用户是否设置了密码
	if user.Password == nil {
		return errors.New("user has no password set, please use set password endpoint")
	}

	// 验证当前密码
	if !s.VerifyPassword(user.Password, req.CurrentPassword) {
		return errors.New("current password is incorrect")
	}

	// 加密新密码
	hashedPassword, err := password.HashPassword(req.NewPassword)
	if err != nil {
		s.base.Logger.Error("Failed to hash new password", zap.Error(err))
		return errors.New("failed to process new password")
	}

	// 更新密码
	user.Password = &hashedPassword
	now := time.Now()
	user.UpdatedAt = &now

	// 保存更新
	if err := s.dao.UserDAO.Update(ctx, user); err != nil {
		return err
	}
	return nil
}

// SetUserPassword 为用户设置密码（适用于OAuth用户）
func (s *UserService) SetUserPassword(ctx *gin.Context, userID string, req *model.UserPasswordSetRequest) error {
	// 获取用户
	user, err := s.dao.UserDAO.GetByID(ctx, userID)
	if err != nil {
		return err
	}
	if user == nil {
		return errors.New("user not found")
	}

	// 检查用户是否已经设置了密码（包括空字符串的情况）
	if user.Password != nil && *user.Password != "" {
		return errors.New("user already has password set, please use update password endpoint")
	}

	// 加密新密码
	hashedPassword, err := password.HashPassword(req.NewPassword)
	if err != nil {
		s.base.Logger.Error("Failed to hash new password", zap.Error(err))
		return errors.New("failed to process new password")
	}

	// 设置密码
	user.Password = &hashedPassword
	now := time.Now()
	user.UpdatedAt = &now

	// 保存更新
	if err := s.dao.UserDAO.Update(ctx, user); err != nil {
		return err
	}

	s.base.Logger.Info("Password set successfully for OAuth user",
		zap.String("userID", userID))
	return nil
}

// GetUserWithOAuthInfo 获取用户信息（包含OAuth和密码状态）
func (s *UserService) GetUserWithOAuthInfo(ctx *gin.Context, userID string) (*db_model.User, bool, error) {
	// 获取用户
	user, err := s.dao.UserDAO.GetByID(ctx, userID)
	if err != nil {
		return nil, false, err
	}
	if user == nil {
		return nil, false, errors.New("user not found")
	}

	// 获取用户的OAuth关联
	oauthUsers, err := s.dao.OAuthUserDAO.GetByUserID(ctx, userID)
	if err != nil {
		return nil, false, err
	}

	// 检查是否有OAuth关联
	hasOAuth := len(oauthUsers) > 0

	return user, hasOAuth, nil
}

// ResetPassword 重置用户密码（忘记密码场景）
func (s *UserService) ResetPassword(ctx *gin.Context, email, plainPassword string) error {
	user, err := s.dao.UserDAO.GetByEmail(ctx, email)
	if err != nil {
		return err
	}
	if user == nil {
		return errors.New("user not found")
	}

	// 检查用户是否已验证邮箱
	if user.VerifiedAt == nil {
		return errors.New("email not verified")
	}

	// 加密新密码
	hashedPassword, err := password.HashPassword(plainPassword)
	if err != nil {
		s.base.Logger.Error("Failed to hash password", zap.Error(err))
		return errors.New("failed to process password")
	}

	// 更新密码
	user.Password = &hashedPassword
	now := time.Now()
	user.UpdatedAt = &now

	if err := s.dao.UserDAO.Update(ctx, user); err != nil {
		return err
	}

	s.base.Logger.Info("Password reset successfully",
		zap.String("email", email))
	return nil
}

// DeleteUser 删除用户
func (s *UserService) DeleteUser(ctx *gin.Context, userID string, req *model.UserDeleteRequest) error {
	// 获取用户
	user, err := s.dao.UserDAO.GetByID(ctx, userID)
	if err != nil {
		return err
	}
	if user == nil {
		return errors.New("user not found")
	}

	// 检查用户是否设置了密码
	if user.Password != nil && *user.Password != "" {
		// 用户有密码，必须提供密码进行验证
		if req.Password == nil {
			return errors.New("password is required for users with password")
		}

		// 解码 base64 编码的密码
		passwordBytes, err := base64.StdEncoding.DecodeString(*req.Password)
		if err != nil {
			return errors.New("invalid password format")
		}
		plainPassword := string(passwordBytes)

		// 验证密码
		if !s.VerifyPassword(user.Password, plainPassword) {
			return errors.New("password is incorrect")
		}
	} else {
		// 用户没有密码，不应该提供密码
		if req.Password != nil {
			return errors.New("password should not be provided for users without password")
		}
	}

	// 删除用户相关的 CAS 数据
	if err := s.cleanupUserCASData(ctx, userID); err != nil {
		s.base.Logger.Error("Failed to cleanup user CAS data",
			zap.String("userID", userID),
			zap.Error(err))
		// 即使清理失败，也继续删除用户，但记录错误
	}

	// 将用户的所有 JWT token 加入黑名单
	if err := s.addUserJWTToBlacklist(ctx, userID); err != nil {
		s.base.Logger.Error("Failed to add user JWT tokens to blacklist",
			zap.String("userID", userID),
			zap.Error(err))
		// 即使黑名单操作失败，也继续删除用户，但记录错误
	}

	// 删除用户
	if err := s.dao.UserDAO.Delete(ctx, userID); err != nil {
		return err
	}

	s.base.Logger.Info("User deleted successfully",
		zap.String("userID", userID))
	return nil
}

// cleanupUserCASData 清理用户相关的 CAS 数据
func (s *UserService) cleanupUserCASData(ctx *gin.Context, userID string) error {
	// 将用户ID转换为UUID
	userUUID, err := uuid.Parse(userID)
	if err != nil {
		return fmt.Errorf("invalid user ID format: %v", err)
	}

	// 获取用户的所有TGT
	tgts, err := s.dao.CasTicketRedisDAO.GetTGTsByPrincipalID(ctx, userUUID)
	if err != nil {
		return fmt.Errorf("failed to get user TGTs: %v", err)
	}

	// 删除所有TGT及相关数据
	for _, tgt := range tgts {
		if err := s.service.CasService.DeleteTGT(ctx, tgt.ID); err != nil {
			s.base.Logger.Warn("Failed to delete TGT during user cleanup",
				zap.String("tgtID", tgt.ID),
				zap.String("userID", userID),
				zap.Error(err))
			// 继续删除其他TGT，不中断流程
		}
	}

	s.base.Logger.Info("User CAS data cleanup completed",
		zap.String("userID", userID),
		zap.Int("tgtCount", len(tgts)))

	return nil
}

// addUserJWTToBlacklist 将用户的所有 JWT token 加入黑名单
func (s *UserService) addUserJWTToBlacklist(ctx *gin.Context, userID string) error {
	// 创建用户 JWT 黑名单键
	userJWTBlacklistKey := constants.JWTBlacklistKey + userID

	// 将用户ID添加到JWT黑名单，设置24小时过期时间
	err := s.base.RedisClient.Set(ctx, userJWTBlacklistKey, "blacklisted", constants.JWTBlacklistLifetime).Err()
	if err != nil {
		return fmt.Errorf("failed to add user JWT to blacklist: %v", err)
	}

	s.base.Logger.Info("User JWT tokens added to blacklist",
		zap.String("userID", userID),
		zap.Duration("lifetime", constants.JWTBlacklistLifetime))

	return nil
}
